package wsj;

import core.*;

import java.io.*;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: lahiru
 * Date: 3/26/14
 * Time: 9:37 PM
 * To change this template use File | Settings | File Templates.
 */
public class CalculateStats {
    public static final double log2 = Math.log(2);
    private static Map<String, List<Double>> h1Distances = new HashMap<String, List<Double>>();     // These distance maps keep the speaker distances between each speaker
    private static Map<String, List<Double>> h2Distances = new HashMap<String, List<Double>>();
    private static Map<String, List<Double>> h3Distances = new HashMap<String, List<Double>>();
    private static Map<String, List<Double>> h4Distances = new HashMap<String, List<Double>>();
    private static Map<String, List<Double>> h5Distances = new HashMap<String, List<Double>>();
    private static Map<String, List<Double>> h6Distances = new HashMap<String, List<Double>>();


    private static Map<Integer, Map<Integer, Double>> h1PhoneDistances = new HashMap<Integer, Map<Integer, Double>>();        //Phoneme distances for each hidden layer
    private static Map<Integer, Map<Integer, Double>> h2PhoneDistances = new HashMap<Integer, Map<Integer, Double>>();
    private static Map<Integer, Map<Integer, Double>> h3PhoneDistances = new HashMap<Integer, Map<Integer, Double>>();
    private static Map<Integer, Map<Integer, Double>> h4PhoneDistances = new HashMap<Integer, Map<Integer, Double>>();
    private static Map<Integer, Map<Integer, Double>> h5PhoneDistances = new HashMap<Integer, Map<Integer, Double>>();
    private static Map<Integer, Map<Integer, Double>> h6PhoneDistances = new HashMap<Integer, Map<Integer, Double>>();


//    private static Map<Integer, List<Double>> h1PhoneDistances = new HashMap<Integer, List<Double>>();
//    private static Map<Integer, List<Double>> h2PhoneDistances = new HashMap<Integer, List<Double>>();
//    private static Map<Integer, List<Double>> h3PhoneDistances = new HashMap<Integer, List<Double>>();
//    private static Map<Integer, List<Double>> h4PhoneDistances = new HashMap<Integer, List<Double>>();
//    private static Map<Integer, List<Double>> h5PhoneDistances = new HashMap<Integer, List<Double>>();
//    private static Map<Integer, List<Double>> h6PhoneDistances = new HashMap<Integer, List<Double>>();

    private static double h1TotalPhoneDistance = 0;
    private static double h2TotalPhoneDistance = 0;
    private static double h3TotalPhoneDistance = 0;
    private static double h4TotalPhoneDistance = 0;
    private static double h5TotalPhoneDistance = 0;
    private static double h6TotalPhoneDistance = 0;

    private static int phoneCount = 42;
    private static boolean euclidean = false;

    private static Map<Integer, HlSpkDistances> averageSpeakerDistances = new HashMap<Integer, HlSpkDistances>();


    public static void main(String[] args) {
        //Read each hidden layer object                                                          //todo move all the hard coded values here
        String location = "/media/Bunty/Academic/Research/speaker-effects/objects/";


        try {
            //read the hiddenlayer1
            FileInputStream fileIn = new FileInputStream(location + "h1.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            HiddenLayer hiddenLayer = (HiddenLayer) in.readObject();
//            printPhonemeVectors(hiddenLayer);
//            accumilateSpeakerDifferences(hiddenLayer);
//            System.out.println(" The size of the h1Distances " + h1Distances.size());

            accumilatePhoneDifferences(hiddenLayer);

            //read the hiddenlayer2

            fileIn = new FileInputStream(location + "h2.ser");
            in = new ObjectInputStream(fileIn);
            hiddenLayer = (HiddenLayer) in.readObject();
//            printPhonemeVectors(hiddenLayer);
//            accumilateSpeakerDifferences(hiddenLayer);
            accumilatePhoneDifferences(hiddenLayer);
//            System.out.println(" The size of the h2Distances " + h2Distances.size());

            //read the hiddenlayer3
            fileIn = new FileInputStream(location + "h3.ser");
            in = new ObjectInputStream(fileIn);
            hiddenLayer = (HiddenLayer) in.readObject();
//            printPhonemeVectors(hiddenLayer);
//            accumilateSpeakerDifferences(hiddenLayer);
            accumilatePhoneDifferences(hiddenLayer);
//            System.out.println(" The size of the h3Distances " + h3Distances.size());

            //read the hiddenlayer4
            fileIn = new FileInputStream(location + "h4.ser");
            in = new ObjectInputStream(fileIn);
            hiddenLayer = (HiddenLayer) in.readObject();
//            printPhonemeVectors(hiddenLayer);
//            accumilateSpeakerDifferences(hiddenLayer);
            accumilatePhoneDifferences(hiddenLayer);
//            System.out.println(" The size of the h4Distances " + h4Distances.size());

            //read the hiddenlayer5
            fileIn = new FileInputStream(location + "h5.ser");
            in = new ObjectInputStream(fileIn);
            hiddenLayer = (HiddenLayer) in.readObject();
//            printPhonemeVectors(hiddenLayer);
            accumilatePhoneDifferences(hiddenLayer);
//            accumilateSpeakerDifferences(hiddenLayer);
//            System.out.println(" The size of the h5Distances " + h5Distances.size());


            //Calculate the trend between speaker distances with different hidden layers
//            printSpeakerTrend(h3Distances,h5Distances);  //todo uncomment

//            printPhonemeTrend(h1PhoneDistances,h3PhoneDistances);


            fileIn = new FileInputStream(location + "h6.ser");
            in = new ObjectInputStream(fileIn);
            hiddenLayer = (HiddenLayer) in.readObject();
//            printPhonemeVectors(hiddenLayer);
            accumilatePhoneDifferences(hiddenLayer);
//            accumilateSpeakerDifferences(hiddenLayer);


//            printPhoneDistances();

            /*
            Print vowel distances
             */
            calculateVowelDistances(h1PhoneDistances, 1);
            calculateVowelDistances(h2PhoneDistances, 2);
            calculateVowelDistances(h3PhoneDistances, 3);
            calculateVowelDistances(h4PhoneDistances, 4);
            calculateVowelDistances(h5PhoneDistances, 5);
            calculateVowelDistances(h6PhoneDistances, 6);

             /*
            Print the core.Phone trend as go up with the hidden layers
             */
//            System.out.println(" ################# Hidden Layer 1 to Hidden Layer 2 ###########################");
//            printPhonemeTrend(h1PhoneDistances, h2PhoneDistances);
//            System.out.println(" ################# Hidden Layer 2 to Hidden Layer 3 ###########################");
//            printPhonemeTrend(h2PhoneDistances, h3PhoneDistances);
//            System.out.println(" ################# Hidden Layer 3 to Hidden Layer 4 ###########################");
//            printPhonemeTrend(h3PhoneDistances, h4PhoneDistances);
//            System.out.println(" ################# Hidden Layer 4 to Hidden Layer 5 ###########################");
//            printPhonemeTrend(h4PhoneDistances, h5PhoneDistances);
//            System.out.println(" ################# Hidden Layer 5 to Hidden Layer 6 ###########################");
//            printPhonemeTrend(h5PhoneDistances, h6PhoneDistances);




            /*
            Print the average and total speaker distances
             */

//            printPhoneDistances();


//            /*
//            Print the speaker trend as go up with the hidden layers
//             */
//            System.out.println(" ################# Hidden Layer 1 to Hidden Layer 2 ###########################");
//            printSpeakerTrend(h1Distances,h2Distances);
//            System.out.println(" ################# Hidden Layer 2 to Hidden Layer 3 ###########################");
//            printSpeakerTrend(h2Distances,h3Distances);
//            System.out.println(" ################# Hidden Layer 3 to Hidden Layer 4 ###########################");
//            printSpeakerTrend(h3Distances,h4Distances);
//            System.out.println(" ################# Hidden Layer 4 to Hidden Layer 5 ###########################");
//            printSpeakerTrend(h4Distances,h5Distances);
//            System.out.println(" ################# Hidden Layer 5 to Hidden Layer 6 ###########################");
//            printSpeakerTrend(h5Distances,h6Distances);
//
//
//
//
//            /*
//            Print the average and total speaker distances
//             */
//
//            printAverageSpeakerDistances();




            /*
            print hidden layer 2 phoneme distances
             */


//            for(int phoneID1 : h2PhoneDistances.keySet()){
//                System.out.println("The phone ID is " + phoneID1);
//                for(int phoneID2 : h2PhoneDistances.get(phoneID1).keySet()){
//                    System.out.println(phoneID2 + " : " + h2PhoneDistances.get(phoneID1).get(phoneID2));
//                }
//            }


//            for (String speakerID : h1Distances.keySet()){
//                //calculate the h1 - h2
//                List<Double> tempList1 = h1Distances.get(speakerID);
//                List<Double> tempList2 = h5Distances.get(speakerID);
//
//                StringBuffer trendSign = new StringBuffer();
////                StringBuffer trendNumbers = new StringBuffer();
//                trendSign.append(" The speaker ID : " + speakerID + " ,");
//                for(int i=0; i<tempList1.size(); i++){
//                    String sign = " WRONG";  //TODO asing global variables
//                    double diff = tempList1.get(i) - tempList2.get(i);
//                    if (diff == 0 ) {
//                        sign = "NOCHANGE";
//                    }else if (diff < 0.0){
//                        sign = "NEGATIVE";
//                    }else if (diff > 0.0){
//                        sign = "POSITIVE";
//                    }
//                    trendSign.append(sign+",");
//
//
//                }
//                trendSign.append("\n");
//                System.out.println(trendSign);
//            }


//            printPhonemCoverage(hiddenLayer1);   //todo uncomment when phoneme coverage is needed to generate
            in.close();
            fileIn.close();
        } catch (IOException i) {
            i.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }


    //    private static void calculateVowelDistances(Map<Integer, List<Double>> phoneDistances , int layerID){
    private static void calculateVowelDistances(Map<Integer, Map<Integer, Double>> phoneDistances, int layerID) {
        String vowelIDs = "5 11 12 16 19 24 28 29 33 35 36 38 41 42";
        List<String> vowels = (Arrays.asList(vowelIDs.split(" ")));
        int comparisons = 0;
        double totalDistance = 0.0;
        for (int i = 0; i < vowels.size(); i++) {
            int phoneID1 = Integer.parseInt(vowels.get(i));
//            List<Double> distances = phoneDistances.get(phoneID1);
            Map<Integer, Double> distances = phoneDistances.get(phoneID1);
            double interDistance = 0.0;

            for (int j = i + 1; j < vowels.size(); j++) {
                comparisons = comparisons + 1;
                int phoneID2 = Integer.parseInt(vowels.get(j));
                interDistance = interDistance + distances.get(phoneID2);
            }
            totalDistance = totalDistance + interDistance;
        }
//        totalDistance = totalDistance * 100000000000000000.0;
        System.out.println("The total distances between vowels for layer " + layerID + " is " + totalDistance);
//        System.out.println("The comparisons " + comparisons);
    }


    private static void printAverageSpeakerDistances() {
        for (HlSpkDistances hlSpkDistances : averageSpeakerDistances.values()) {
            System.out.println("Total Distance for Hidden layer " + hlSpkDistances.getId() + " " + hlSpkDistances.getTotalSpeakerDistance());
            System.out.println("Avg Distance for Hidden layer " + hlSpkDistances.getId() + " " + hlSpkDistances.getAverageSpeakerDistance());
        }
    }


    private static void printPhoneDistances() {
        System.out.println("Total core.Phone Distance for Hidden layer 1 " + h1TotalPhoneDistance);
        System.out.println("Total core.Phone Distance for Hidden layer 1 " + h1TotalPhoneDistance / phoneCount);

        System.out.println("Total core.Phone Distance for Hidden layer 2 " + h2TotalPhoneDistance);
        System.out.println("Total core.Phone Distance for Hidden layer 2 " + h2TotalPhoneDistance / phoneCount);

        System.out.println("Total core.Phone Distance for Hidden layer 3 " + h3TotalPhoneDistance);
        System.out.println("Total core.Phone Distance for Hidden layer 3 " + h3TotalPhoneDistance / phoneCount);

        System.out.println("Total core.Phone Distance for Hidden layer 4 " + h4TotalPhoneDistance);
        System.out.println("Total core.Phone Distance for Hidden layer 4 " + h4TotalPhoneDistance / phoneCount);

        System.out.println("Total core.Phone Distance for Hidden layer 5 " + h5TotalPhoneDistance);
        System.out.println("Total core.Phone Distance for Hidden layer 5 " + h5TotalPhoneDistance / phoneCount);

        System.out.println("Total core.Phone Distance for Hidden layer 6 " + h6TotalPhoneDistance);
        System.out.println("Total core.Phone Distance for Hidden layer 6 " + h6TotalPhoneDistance / phoneCount);

    }


    private static void printPhonemeVectors(HiddenLayer hiddenLayer) throws IOException {
        Map<Integer, PhoneWrapper> phoneWrapperMap = new HashMap<Integer, PhoneWrapper>();

        for (Speaker speaker : hiddenLayer.getSpeakerList()) {
            Map<Integer, Phone> phones = speaker.getPhones();
            for (int i = 1; i <= phones.size(); i++) {
                Phone phone;
                if (phones.get(i) == null) {
                    continue;
                }
                phone = phones.get(i);
                int phoneID = phone.getId();

                if (phoneWrapperMap.get(phoneID) == null) {
                    phoneWrapperMap.put(phoneID, new PhoneWrapper(phone));
                } else {
                    PhoneWrapper phoneWrapper = phoneWrapperMap.get(phoneID);
                    phoneWrapper.addActivations(phone.getVector());
                    phoneWrapper.increaseCount(phone.getCount());
                    phoneWrapperMap.put(phone.getId(), phoneWrapper);
                }
            }
        }

        List<Object> phoneIdList = Arrays.asList(phoneWrapperMap.keySet().toArray());

//        double totalDistance = 0.0;
//        int hiddenLayerId = hiddenLayer.getId();

//        Average all the phonemeHiddenActivation Vectors
        for (int i = 0; i < phoneIdList.size(); i++) {
            int phoneID = (Integer) phoneIdList.get(i);
            PhoneWrapper phoneWrapper = phoneWrapperMap.get(phoneID);
            phoneWrapper.averageVector();
            phoneWrapperMap.put(phoneID, phoneWrapper);

        }


        double threshold = 0.25; // todo change this


        //start writing the arff file for weka clustering
        FileWriter fileWriter = new FileWriter("/home/lahiru/workspace/hiddenLayer" + hiddenLayer.getId() + ".arff");  //todo configure
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

        bufferedWriter.write("@relation phonemes");
        bufferedWriter.newLine();
        bufferedWriter.newLine();

        //write about attributes
        int numAttributes = 2048; //todo make this configurable
        for (int h = 1; h <= numAttributes; h++) {
            bufferedWriter.write("@attribute h" + h + " numeric\n");
        }
        bufferedWriter.newLine();
        bufferedWriter.newLine();

        bufferedWriter.write("@data\n");
        bufferedWriter.newLine();
        bufferedWriter.newLine();


        for (int i = 0; i < phoneIdList.size(); i++) {
            int phoneID1 = (Integer) phoneIdList.get(i);
            int totalCount = 0;
//            int phoneID1 = 12;
            double[] vector1 = phoneWrapperMap.get(phoneID1).getVector();
            int numHiddenUnits = vector1.length;
            int[] psi = new int[numHiddenUnits];
            for (int j = 0; j < phoneIdList.size(); j++) {
                int phoneID2 = (Integer) phoneIdList.get(j);
//                int phoneID2 = 13;
                double[] vector2 = phoneWrapperMap.get(phoneID2).getVector();
                int count = 0;
                for (int k = 0; k < numHiddenUnits; k++) {
                    if (Math.abs(vector1[k] - vector2[k]) > threshold) {
                        psi[k] = psi[k] + 1;
                        count++;
                    }
                }

                totalCount = totalCount + count;

            }


            int length = psi.length;
            StringBuffer sb = new StringBuffer();
            for (int p = 0; p < length; p++) {
                if (p == length - 1) {
                    sb.append(psi[p] + "\n");
                } else {
                    sb.append(psi[p] + ",");
                }
            }
            bufferedWriter.write(sb.toString());


//            System.out.println(sb.toString());
//
//            System.out.println("TotalCount " + totalCount);
        }

        bufferedWriter.close();


//        int phoneID = 1;
//        core.PhoneWrapper phoneWrapper= phoneWrapperMap.get(phoneID); //Just ot check
//        double[] hactivations = phoneWrapper.getVector();
//        Arrays.sort(hactivations);
//        int length = hactivations.length;
//        double[][] plotData = new double[length][2];
//        for(int i=0; i<length;i++){
//              plotData[i][0] = i+1;
//              plotData[i][1] = hactivations[length-1-i];
////              plotData[i][1] = hactivations[i];
//        }
//
//        JavaPlot p = new JavaPlot();
//
//        PostscriptTerminal epsf = new PostscriptTerminal(System.getProperty("user.home")
//                + System.getProperty("file.separator") + phoneID +".eps");
//        epsf.setColor(true);
//        p.setTerminal(epsf);
//        p.addPlot(plotData);
//        p.plot();


    }

    private static void accumilatePhoneDifferences(HiddenLayer hiddenLayer) {

        Map<Integer, PhoneWrapper> phoneWrapperMap = new HashMap<Integer, PhoneWrapper>();

        for (Speaker speaker : hiddenLayer.getSpeakerList()) {
            Map<Integer, Phone> phones = speaker.getPhones();
            for (int i = 1; i <= phones.size(); i++) {
                Phone phone;
                if (phones.get(i) == null) {
                    continue;
                }
                phone = phones.get(i);
                int phoneID = phone.getId();

                if (phoneWrapperMap.get(phoneID) == null) {
                    phoneWrapperMap.put(phoneID, new PhoneWrapper(phone));
                } else {
                    PhoneWrapper phoneWrapper = phoneWrapperMap.get(phoneID);
                    phoneWrapper.addActivations(phone.getVector());
                    phoneWrapper.increaseCount(phone.getCount());
                    phoneWrapperMap.put(phone.getId(), phoneWrapper);
                }
            }
        }

        List<Object> phoneIdList = Arrays.asList(phoneWrapperMap.keySet().toArray());

        double totalDistance = 0.0;
        int hiddenLayerId = hiddenLayer.getId();

//        Average all the phonemeHiddenActivation Vectors
        for (int i = 0; i < phoneIdList.size(); i++) {
            int phoneID = (Integer) phoneIdList.get(i);
            PhoneWrapper phoneWrapper = phoneWrapperMap.get(phoneID);
            phoneWrapper.averageVector();
            phoneWrapperMap.put(phoneID, phoneWrapper);

        }

//        System.out.println("The size of the phoneWrapperMap " + phoneWrapperMap.size());

        for (int i = 0; i < phoneIdList.size(); i++) {                 // TODO Do not include silence 0, SPN 1, NSN 2 in calculations

//            List<Double> distanceVector = new ArrayList<Double>();
            Map<Integer, Double> distanceVector = new HashMap<Integer, Double>();

            int phoneID1 = (Integer) phoneIdList.get(i);

//            if(phoneID1==0 || phoneID1==1 || phoneID1==2){
//                continue;
//            }
            PhoneWrapper phoneWrapper1 = phoneWrapperMap.get(phoneID1);
//            phoneWrapper1.averageVector();
//            speakerDistances.append(speakerID1 +" ,");
            for (int j = 0; j < phoneIdList.size(); j++) {
                int phoneID2 = (Integer) phoneIdList.get(j);
//                if(phoneID2==0 || phoneID2==1 || phoneID2==2){
//                    continue;
//                }
                PhoneWrapper phoneWrapper2 = phoneWrapperMap.get(phoneID2);
//                phoneWrapper2.averageVector();
//                    speakerDistances.append(speakerID2 +" ,");


                //Calculate the distance between two phones
                double distance;
                if (euclidean) {
                    distance = calculateEuclideanDistance(phoneWrapper1.getVector(), phoneWrapper2.getVector());
                } else {
                    distance = calculateKLDivergenceVectors(phoneWrapper1.getVector(), phoneWrapper2.getVector());
//                    String dist = distance+"";
//                    if(dist.equals("NaN")){
//                        System.out.println("distance is NaN " + phoneID1 + " " + phoneID2);
//                    }
                }


//                if(Double.isNaN(distance)){
//                }
//                distanceVector.add(distance);
                distanceVector.put(phoneID2, distance);
                totalDistance = totalDistance + distance;
//                    speakerDistances.append(distance +" ,");
            }
//            speakerDistances.append("\n");
            if (hiddenLayerId == 1) {
                h1PhoneDistances.put(phoneID1, distanceVector);
            } else if (hiddenLayerId == 2) {
                h2PhoneDistances.put(phoneID1, distanceVector);
            } else if (hiddenLayerId == 3) {
                h3PhoneDistances.put(phoneID1, distanceVector);
            } else if (hiddenLayerId == 4) {
                h4PhoneDistances.put(phoneID1, distanceVector);
            } else if (hiddenLayerId == 5) {
                h5PhoneDistances.put(phoneID1, distanceVector);
            } else if (hiddenLayerId == 6) {
                h6PhoneDistances.put(phoneID1, distanceVector);
            }
        }

        if (hiddenLayerId == 1) {
            h1TotalPhoneDistance = totalDistance;
        } else if (hiddenLayerId == 2) {
            h2TotalPhoneDistance = totalDistance;
        } else if (hiddenLayerId == 3) {
            h3TotalPhoneDistance = totalDistance;
        } else if (hiddenLayerId == 4) {
            h4TotalPhoneDistance = totalDistance;
        } else if (hiddenLayerId == 5) {
            h5TotalPhoneDistance = totalDistance;
        } else if (hiddenLayerId == 6) {
            h6TotalPhoneDistance = totalDistance;
        }


    }


    private static void printPhonemeTrend(Map<Integer, List<Double>> first, Map<Integer, List<Double>> second) {
        for (int phoneID = 1; phoneID <= first.keySet().size(); phoneID++) {             // TODO Do not include silence 0, SPN 1, NSN 2 in calculations
//        for (int phoneID : first.keySet()){
            List<Double> tempList1 = first.get(phoneID);
            List<Double> tempList2 = second.get(phoneID);

            StringBuffer trendSign = new StringBuffer();
            StringBuffer countSign = new StringBuffer();
//                StringBuffer trendNumbers = new StringBuffer();
            trendSign.append(" The phoneID : " + phoneID + " ,");
            countSign.append(" The phoneID : " + phoneID + " ,");

            int countPositives = 0;
            int countNegatives = 0;
            int countNochanges = 0;

            for (int i = 0; i < tempList1.size(); i++) {
                String sign = " WRONG";  //TODO asing global variables

                double diff = tempList1.get(i) - tempList2.get(i);
                if (diff == 0) {
                    sign = "NOCHANGE";
                    countNochanges++;
                } else if (diff < 0.0) {
                    sign = "DECREASING";
                    countNegatives++;
                } else if (diff > 0.0) {
                    sign = "INCREASING";
                    countPositives++;
                }
                trendSign.append(sign + ",");
//                trendSign.append(tempList2.get(i)+",");
            }
            trendSign.append("\n");
            countSign.append(countNegatives + " , " + countPositives + " , " + countNochanges + "\n");
            System.out.println(trendSign);
//            System.out.println(countSign);
        }
    }


    private static void printSpeakerTrend(Map<String, List<Double>> first, Map<String, List<Double>> second) {
        for (String speakerID : first.keySet()) {
            List<Double> tempList1 = first.get(speakerID);
            List<Double> tempList2 = second.get(speakerID);

            StringBuffer trendSign = new StringBuffer();
            StringBuffer countSign = new StringBuffer();
//                StringBuffer trendNumbers = new StringBuffer();
            trendSign.append(" The speaker ID : " + speakerID + " ,");
            countSign.append(" The speaker ID : " + speakerID + " ,");

            int countPositives = 0;
            int countNegatives = 0;
            int countNochanges = 0;

            for (int i = 0; i < tempList1.size(); i++) {
                String sign = " WRONG";  //TODO asing global variables

                double firstDouble = tempList1.get(i);
                double secondDouble = tempList2.get(i);

                if (Double.isNaN(firstDouble)) {
                    System.err.println("The firstDouble is NaN for " + speakerID + " index " + i);
                }

                if (Double.isNaN(secondDouble)) {
                    System.err.println("The secondDouble is NaN for " + speakerID + " index " + i);
                }

                double diff = tempList1.get(i) - tempList2.get(i);
                if (diff == 0) {
                    sign = "NOCHANGE";
                    countNochanges++;
                } else if (diff < 0.0) {
                    sign = "DECREASING";
                    countNegatives++;
                } else if (diff > 0.0) {
                    sign = "INCREASING";
                    countPositives++;
                }
                trendSign.append(sign + ",");
//                trendSign.append(tempList2.get(i)+",");
            }
            trendSign.append("\n");
            countSign.append(countNegatives + " , " + countPositives + " , " + countNochanges + "\n");
//            System.out.println(trendSign);

//            System.out.println(" ################# Counts  ###########################");
            System.out.println(countSign);
        }
    }


    /*
       Needs to get an averaged vector for each speaker and  calculate the KL Divergence between them
        */
    private static void accumilateSpeakerDifferences(HiddenLayer hiddenLayer) {

        Map<String, double[]> speakerVectors = new HashMap<String, double[]>(40);

        for (Speaker speaker : hiddenLayer.getSpeakerList()) {
            int count = 0;
            double speakerVector[] = new double[2048];//TODO global variables for this value
            for (Phone phone : speaker.getPhones().values()) {
                count = count + phone.getCount();
                double newVector[] = phone.getVector();
                if (newVector.length != speakerVector.length) {
                    throw new NumberFormatException();
                }

                for (int i = 0; i < speakerVector.length; i++) {
                    speakerVector[i] = 0.0;
                }

                for (int i = 0; i < speakerVector.length; i++) {
                    speakerVector[i] = speakerVector[i] + newVector[i];
//                    System.out.println(speakerVector[i]);
//                    System.out.println(newVector[i]);
                }
            }
//            System.out.println("The count for speaker is " + count);
            //average speaker vector by count
            for (int i = 0; i < speakerVector.length; i++) {
                speakerVector[i] = speakerVector[i] / count;

            }

            speakerVectors.put(speaker.getId(), speakerVector);
//            System.out.println("The size of the speaker vector is " + speakerVector.length);

        }

        List<Object> speakerList = Arrays.asList(speakerVectors.keySet().toArray());
//        StringBuffer speakerDistances = new StringBuffer();
//        speakerDistances.append("####### \n");

        double totalDistance = 0.0;
        int hiddenLayerId = hiddenLayer.getId();

        for (int i = 0; i < speakerList.size(); i++) {

            List<Double> distanceVector = new ArrayList<Double>(40);  //TODO number of speakers

            String speakerID1 = (String) speakerList.get(i);
//            speakerDistances.append(speakerID1 +" ,");
            for (int j = 0; j < speakerList.size(); j++) {
                String speakerID2 = (String) speakerList.get(j);
//                    speakerDistances.append(speakerID2 +" ,");
                //Calculate the distance between two speakers

                double distance;
                if (euclidean) {
                    distance = calculateEuclideanDistance(speakerVectors.get(speakerID1), speakerVectors.get(speakerID2));
                } else {
                    distance = calculateKLDivergenceVectors(speakerVectors.get(speakerID1), speakerVectors.get(speakerID2));
                }


//                double distance = calculateKLDivergenceVectors(speakerVectors.get(speakerID1), speakerVectors.get(speakerID2));

                if (Double.isNaN(distance)) {
                    System.err.println("The distance is NaN for " + speakerID1 + " and " + speakerID2);
                }

                totalDistance = totalDistance + distance;
                distanceVector.add(distance);
//                    speakerDistances.append(distance +" ,");
            }
//            speakerDistances.append("\n")
            if (hiddenLayerId == 1) {
                h1Distances.put(speakerID1, distanceVector);
            } else if (hiddenLayerId == 2) {
                h2Distances.put(speakerID1, distanceVector);
            } else if (hiddenLayerId == 3) {
                h3Distances.put(speakerID1, distanceVector);
            } else if (hiddenLayerId == 4) {
                h4Distances.put(speakerID1, distanceVector);
            } else if (hiddenLayerId == 5) {
                h5Distances.put(speakerID1, distanceVector);
            } else if (hiddenLayerId == 6) {
                h6Distances.put(speakerID1, distanceVector);
            }
        }


        if (hiddenLayerId == 1) {
            HlSpkDistances hlSpkDistances = new HlSpkDistances();
            hlSpkDistances.setId(hiddenLayerId);
            hlSpkDistances.setTotalSpeakerDistance(totalDistance);
            hlSpkDistances.setAverageSpeakerDistance(totalDistance / (40 * 39)); //TODO remove hard coded values
            averageSpeakerDistances.put(hiddenLayerId, hlSpkDistances);
        } else if (hiddenLayerId == 2) {
            HlSpkDistances hlSpkDistances = new HlSpkDistances();
            hlSpkDistances.setId(hiddenLayerId);
            hlSpkDistances.setTotalSpeakerDistance(totalDistance);
            hlSpkDistances.setAverageSpeakerDistance(totalDistance / (40 * 39)); //TODO remove hard coded values
            averageSpeakerDistances.put(hiddenLayerId, hlSpkDistances);
        } else if (hiddenLayerId == 3) {
            HlSpkDistances hlSpkDistances = new HlSpkDistances();
            hlSpkDistances.setId(hiddenLayerId);
            hlSpkDistances.setTotalSpeakerDistance(totalDistance);
            hlSpkDistances.setAverageSpeakerDistance(totalDistance / (40 * 39)); //TODO remove hard coded values
            averageSpeakerDistances.put(hiddenLayerId, hlSpkDistances);
        } else if (hiddenLayerId == 4) {
            HlSpkDistances hlSpkDistances = new HlSpkDistances();
            hlSpkDistances.setId(hiddenLayerId);
            hlSpkDistances.setTotalSpeakerDistance(totalDistance);
            hlSpkDistances.setAverageSpeakerDistance(totalDistance / (40 * 39)); //TODO remove hard coded values
            averageSpeakerDistances.put(hiddenLayerId, hlSpkDistances);
        } else if (hiddenLayerId == 5) {
            HlSpkDistances hlSpkDistances = new HlSpkDistances();
            hlSpkDistances.setId(hiddenLayerId);
            hlSpkDistances.setTotalSpeakerDistance(totalDistance);
            hlSpkDistances.setAverageSpeakerDistance(totalDistance / (40 * 39)); //TODO remove hard coded values
            averageSpeakerDistances.put(hiddenLayerId, hlSpkDistances);
        } else if (hiddenLayerId == 6) {
            HlSpkDistances hlSpkDistances = new HlSpkDistances();
            hlSpkDistances.setId(hiddenLayerId);
            hlSpkDistances.setTotalSpeakerDistance(totalDistance);
            hlSpkDistances.setAverageSpeakerDistance(totalDistance / (40 * 39)); //TODO remove hard coded values
            averageSpeakerDistances.put(hiddenLayerId, hlSpkDistances);
        }
//        System.out.println(speakerDistances.toString());
//        System.out.println(" the key set is " );

//        System.out.println("The size of the speaker vectors map is " + speakerVectors.size() + " " + System.currentTimeMillis());
    }

    private static double calculateKLDivergenceVectors(double[] vector1, double[] vector2) throws NumberFormatException {
        int length = vector1.length;
        if (length != vector2.length) {
            throw new NumberFormatException("Vector length's are not matching ");
        }

        if (vector1.length != 2048) {
            System.out.println("vector lengths are wrong ");
        }

        double kLdiv = 0.0;
        for (int i = 0; i < length; i++) {

            String vector1s = vector1[i] + "";
            String vector2s = vector2[i] + "";

            if (vector1s.equals("NaN")) {
                System.out.println("The vector1 is NaN " + i);
            }

            if (vector2s.equals("NaN")) {
                System.out.println("The vector2 is NaN " + i);
            }

            double temp = klDivergence(vector1[i], vector2[i]);
            String temps = temp + "";
            if (temps.equals("NaN")) {
//                System.out.println("The temp is NaN " + i);
//                System.out.println(vector1[i]);
//                System.out.println(vector2[i]);
                temp = 0.0; //todo change
            }


//            kLdiv = kLdiv + klDivergence(vector1[i], vector2[i]);
            kLdiv = kLdiv + temp;
//            System.out.println("temp " + temp);
        }

        return kLdiv / length;  //To change body of created methods use File | Settings | File Templates.
    }


    public static double calculateEuclideanDistance(double[] array1, double[] array2) {
        int length = array1.length;
        if (length != array2.length) {
            throw new NumberFormatException("Vector length's are not matching ");
        }

        double Sum = 0.0;
        for (int i = 0; i < array1.length; i++) {
            Sum = Sum + Math.pow((array1[i] - array2[i]), 2.0);
        }
        return Math.sqrt(Sum);
    }

    private static void printPhonemCoverage(HiddenLayer hiddenLayer) {
        StringBuffer coverageReport = new StringBuffer();
        coverageReport.append("#############  Phoneme Coverage ################## \n");
        coverageReport.append("core.Speaker ID ,");
        for (int i = 1; i <= 42; i++) {
            coverageReport.append("core.Phone " + i + ",");
        }
        coverageReport.append("\n");

        for (Speaker speaker : hiddenLayer.getSpeakerList()) {
            coverageReport.append("core.Speaker " + speaker.getId() + ",");
            for (int i = 1; i <= 42; i++) {
                int count = 0;
                Phone phone = speaker.getPhones().get(i);
                if (phone != null) {
                    count = phone.getCount();
                }
                coverageReport.append(count + ",");
//            System.out.println(i + " " +count);
            }
            coverageReport.append("\n");
        }

        System.out.println(coverageReport.toString());

    }

    public static double klDivergence(double p1, double p2) {


        double klDiv = 0.0;

        if (p1 == 0.0 || p2 == 0.0) {
            return klDiv;
        } else {
//            return ((p1 * Math.log(p1 / p2)) + ((1 - p1) * Math.log((1 - p1) / (1 - p2)))) / log2;
            return (((p1 * Math.log(p1 / p2)) + ((1 - p1) * Math.log((1 - p1) / (1 - p2)))) + ((p2 * Math.log(p2 / p1)) + ((1 - p2) * Math.log((1 - p2) / (1 - p1))))) / log2;
        }

    }
}
